# controller

# responsible for the build of the storage-screen
# main task is to display the different user-information
# puts the html-pieces together

# SOME IMPORTANT INFORMATION:
# Documentation about how-to upload keys into S3
# http://docs.amazonwebservices.com/AmazonS3/latest/index.html?HTTPPOSTForms.html
# http://doc.s3.amazonaws.com/proposals/post.html
# http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434
# http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html
#
# Documentation about how-to user the GAE Blobstore
# http://code.google.com/intl/de-DE/appengine/docs/python/blobstore/overview.html

from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

from dateutil.parser import *
from ConfigParser import SafeConfigParser
from google.appengine.ext.blobstore import blobstore
parser = SafeConfigParser()

from Utilities import *

import cgi
form = cgi.FieldStorage()

import httplib
import urllib

from google.appengine._internal.django.core.files.uploadedfile import SimpleUploadedFile


class BuildStorageInfo(webapp.RequestHandler):  
    # by default the isSync attribute is 'true' because else it is set to 'false' in the relevant processes...
    def get(self, pSelf, templateValues, keyList, isSync='true'):
        utilities = Utilities()
        
        key = pSelf.request.get('key')
        
        # menu-text
        credentialsText = utilities.getMenuTextCredentials()
        yourDataText = utilities.getMenuTextYourData()
        infoText = utilities.getMenuTextInfo()
        
        # get data for some place-holder
        title = utilities.getTitleText()
        userText = templateValues['userText']
        username = templateValues['user']
        url = templateValues['url']
        urlText = templateValues['urlText']
        hintText = templateValues['hintText']
        hintColor = templateValues['hintColor']
        
        # bucket-information
#        bucketnameText = _('Bucketname: ')
        bucketnameText = 'Bucketname: '
        bucketname = utilities.getBucketname(username)
        
        regionnameList = self.getRegionnames(utilities, username)
        raidLevel = utilities.getRaidLevel(username)
        
        # data for some other place-holder
        headline = self.buildHeadline()
        entryListHeadline = self.buildEntryListHeadline()
        entryListTable = self.buildEntryTable(pSelf, username, utilities, keyList, isSync, regionnameList, raidLevel)
        selectFileHeadline = self.buildSelectFileHeadline()
        
        # prepare different things for file-upload
        policyDocument = self.buildPolicyDocument(utilities, bucketname)
        policy = utilities.encodePolicyDocument(policyDocument)
        
        selectFile = self.selectFile(utilities, username, bucketname, policy, key)
        
        finalTemplateValues = {
                               'title': title,
                               'userText': userText,
                               'user': username,
                               'url': url,
                               'urlText': urlText,
                               'hintText': hintText,
                               'hintColor': hintColor,
                               'credentials': credentialsText,
                               'yourData': yourDataText,
                               'info': infoText,
                               'headline': headline,
                               'bucketnameText': bucketnameText,
                               'bucketname': bucketname,
                               'entryListHeadline': entryListHeadline,
                               'entryListTable': entryListTable,
                               'selectFileHeadline': selectFileHeadline,
                               'selectFile': selectFile
                               }
        
        html = template.render('view/templates/selectdata.html', finalTemplateValues)
        
        pSelf.response.out.write(html)
        
    # responsible for the headline-text in the menu 'Your Data'    
    def buildHeadline(self):
#        headline = _('File upload and Access-Control-List management')
        headline = 'File upload and Access-Control-List management'
        return headline
    
    # responsible for the entry-list-text above the entry-list-table
    def buildEntryListHeadline(self):
#        entryListHeadline = _('Entry-List (Keys)')
        entryListHeadline = 'Entry-List (Keys)'
        return entryListHeadline
    
    # responsible for the build of the table with the entries (also called 'buckets') - like the credential-table
    def buildEntryTable(self, pSelf, username, utilities, keyList, isSync, regionnameList, raidLevel):
        # get the raid-level-values/-names
        raidFive = utilities.getRaidFiveText()
        raidOne = utilities.getRaidOneText()
        
        # get the storage-service-names
        amazon = utilities.getAmazonText()
        google = utilities.getGoogleText()
        openStack = utilities.getOpenStackText()

        # get the credentials..        
        credentials = utilities.getCredentials(username)
        credentialAmount = credentials.count()
        
        # build the key-table
        entryListTable = ''
        entryListTable = entryListTable + '<table border="1" cellspacing="0" cellpadding="5">'
        entryListTable = entryListTable + '<tr>'
        entryListTable = entryListTable + '<th>&nbsp;&nbsp;&nbsp;</th>'
#        entryListTable = entryListTable + '<th align="center">' + _('Keys') + '</th>'
#        entryListTable = entryListTable + '<th align="center">' + _('Filesize') + '</th>'
#        entryListTable = entryListTable + '<th align="center">' + _('Last Modified') + '</th>'
#        entryListTable = entryListTable + '<th align="center">' + _('Access Control List') + '</th>'
#        entryListTable = entryListTable + '<th align="center">' + _('MD5 checksum') + '</th>'
        entryListTable = entryListTable + '<th align="center">' + 'Keys' + '</th>'
        entryListTable = entryListTable + '<th align="center">' + 'Filesize' + '</th>'
        entryListTable = entryListTable + '<th align="center">' + 'Last Modified' + '</th>'
        entryListTable = entryListTable + '<th align="center">' + 'Access Control List' + '</th>'
        entryListTable = entryListTable + '<th align="center">' + 'MD5 Checksum' + '</th>'
        entryListTable = entryListTable + '</tr>'
        
        # initialize some necessary attributes
        keyname = None
        fileSize = None
        lastModified = None
        md5 = None
        
        # if we are under raid-5, we must use the local database (OctopusCloudDatabaseRaidFive) to present the information in the view...
        if raidLevel == raidFive and credentialAmount == 3:
            localKeyList = self.getEntriesFromLocalDatabaseRaidFive(utilities, username)

            if localKeyList:
                for i in range(len(localKeyList)):
                    keyname = localKeyList[i].filename
                    fileSize = localKeyList[i].filesize
#                    lastModified = parse(localKeyList[i].lastModified)
                    lastModified = localKeyList[i].lastModified
                    md5 = localKeyList[i].md5File
                    
                    entryListTable = self.buildKeyTableEntry(entryListTable, localKeyList, i, keyname, fileSize, lastModified, md5, raidLevel, raidOne, raidFive, credentialAmount)
                    
        # if we are under raid-1 or have only one available storage-service, we can use the key-list from the parameter-list
        if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
            if keyList:
                for i in range(len(keyList)):
                    if regionnameList.__contains__(amazon) or regionnameList.__contains__(google):
                        keyname = keyList[i].name
                        fileSize = keyList[i].size
                        lastModified = parse(keyList[i].last_modified)
                        md5 = utilities.convertMD5Outline(username, keyList, i)

                    if regionnameList.__contains__(openStack):
                        keyname = keyList[i].name
                        fileSize = keyList[i].size
                        lastModified = parse(keyList[i].last_modified)
                        md5 = utilities.getMD5ChecksumForOpenstackByKeyname(keyname, fileSize)
                        md5 = str(md5)
                        
                    entryListTable = self.buildKeyTableEntry(entryListTable, keyList, i, keyname, fileSize, lastModified, md5, raidLevel, raidOne, raidFive, credentialAmount)
            
            #=======================================================================================================================================================================
            #        if keyname != None and fileSize != None and lastModified != None and md5 != None:        
            #            entryListTable = entryListTable + '<tr>'
            #            entryListTable = entryListTable + '<td>'
            # #                entryListTable = entryListTable + '<a href="/deletebucketkey?md5hash=' + md5 + '" title="erase key">'      
            #            entryListTable = entryListTable + '<a href="/deletebucketkey?md5hash='      
            #            entryListTable = entryListTable + md5            
            #            entryListTable = entryListTable + '" title="erase key">'            
            #            entryListTable = entryListTable + '<img src="view/images/trash2.png" width="20" height="20" border="0" alt="erase key">'
            #            entryListTable = entryListTable + '</a>'
            #            entryListTable = entryListTable + '</td>'
            #        
            #            # merge the file-parts together, when the raid-level is raid-5
            #            if raidLevel == raidFive and credentialAmount == 3:
            #                entryListTable = entryListTable + '<td>'
            #                entryListTable = entryListTable + '<a href="/mergefile?keyname=' + keyname + '&amp;md5hash=' + md5 + '" title="merge file">'
            #                entryListTable = entryListTable + keyname
            #                entryListTable = entryListTable + '</a>'
            #                entryListTable = entryListTable + '</td>'
            #        
            #            # get the file from one of the storage-services
            #            if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
            #                entryListTable = entryListTable + '<td>'
            #                entryListTable = entryListTable + '<a href="' + keyList[i].generate_url(600, method='GET', headers=None, query_auth=True, force_http=False).replace('&', '&amp;').replace('&amp;amp;', '&amp;') + '">'
            #                entryListTable = entryListTable + keyname
            #                entryListTable = entryListTable + '</a>'
            #                entryListTable = entryListTable + '</td>'
            #            
            #            entryListTable = entryListTable + '<td align="right">' + str(fileSize) + '</td>'
            #            entryListTable = entryListTable + '<td>' + str(lastModified.strftime("%Y-%m-%d  %H:%M:%S")) + '</td>'
            #                
            #            entryListTable = entryListTable + '<td align="center">'
            #            entryListTable = entryListTable + '<a href="/viewacl?key=' + keyname + '&amp;md5hash=' + md5 + '" title="view/edit ACL">'
            #    #                entryListTable = entryListTable + _('view/edit ACL')
            #    #                entryListTable = entryListTable + 'view/edit ACL'
            #            entryListTable = entryListTable + '<img src="view/images/edit.png" width="20" height="20" border="0" alt="view/edit">'
            #            entryListTable = entryListTable + '</a>'
            #            entryListTable = entryListTable + '</td>'
            #            
            #            entryListTable = entryListTable + '<td align="center">'
            #            entryListTable = entryListTable + '<tt>' + md5 + '</tt>'
            #            entryListTable = entryListTable + '</td>'
            #            
            #            entryListTable = entryListTable + '</tr>'
            #=======================================================================================================================================================================
                
        entryListTable = entryListTable + '</table>'
        
        # build the button 'delete all keys'
        entryListTable = entryListTable + '<p></p>'
        entryListTable = entryListTable + '<table>'
        entryListTable = entryListTable + '<form action="/deleteallbucketkeys" method="post" accept-charset="utf-8">'
        entryListTable = entryListTable + '<a href="/deleteallbucketkeys" title="delete all key">'
#        entryListTable = entryListTable + '<input type="submit" value="' + _('Delete all keys') + '">'
        entryListTable = entryListTable + '<input type="submit" value="' + 'Delete all keys' + '">'
        entryListTable = entryListTable + '</a>'
        entryListTable = entryListTable + '</form>'
        
        if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
            # check if the storages are sync...
            if isSync == 'false':
                # build the button 'synchronize'
                entryListTable = entryListTable + '<form action="/synchronize" method="post" accept-charset="utf-8">'
                entryListTable = entryListTable + '<a href="/synchronize" title="synchronize">'
#                entryListTable = entryListTable + '<input type="submit" value="' + _('Synchronize') + '">'
                entryListTable = entryListTable + '<input type="submit" value="' + 'Synchronize' + '">'
                entryListTable = entryListTable + '</a>'
                entryListTable = entryListTable + '</form>'
            
        entryListTable = entryListTable + '</table>'
        
        return entryListTable
    
    # build-up the key-table-entries
    def buildKeyTableEntry(self, entryListTable, keyList, i, keyname, fileSize, lastModified, md5, raidLevel, raidOne, raidFive, credentialAmount):
        if keyname != None and fileSize != None and lastModified != None and md5 != None:        
            entryListTable = entryListTable + '<tr>'
            entryListTable = entryListTable + '<td>'
#                entryListTable = entryListTable + '<a href="/deletebucketkey?md5hash=' + md5 + '" title="erase key">'      
            entryListTable = entryListTable + '<a href="/deletebucketkey?md5hash='      
            entryListTable = entryListTable + md5            
            entryListTable = entryListTable + '" title="erase key">'            
#            entryListTable = entryListTable + '<img src="view/images/trash2.png" width="20" height="20" border="0" alt="erase key">'
            entryListTable = entryListTable + '<img src="view/images/OctopusIconsScratch/01_Scratch/trash_full.png" width="28" height="28" border="0" alt="erase key">'
            entryListTable = entryListTable + '</a>'
            entryListTable = entryListTable + '</td>'
        
            # merge the file-parts together, when the raid-level is raid-5
            if raidLevel == raidFive and credentialAmount == 3:
                entryListTable = entryListTable + '<td>'
                entryListTable = entryListTable + '<a href="/mergefile?keyname=' + keyname + '&amp;md5hash=' + md5 + '" title="merge file">'
                entryListTable = entryListTable + keyname
                entryListTable = entryListTable + '</a>'
                entryListTable = entryListTable + '</td>'
        
            # get the file from one of the storage-services
            if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
                entryListTable = entryListTable + '<td>'
                entryListTable = entryListTable + '<a href="' + keyList[i].generate_url(600, method='GET', headers=None, query_auth=True, force_http=False).replace('&', '&amp;').replace('&amp;amp;', '&amp;') + '">'
                entryListTable = entryListTable + keyname
                entryListTable = entryListTable + '</a>'
                entryListTable = entryListTable + '</td>'
            
            entryListTable = entryListTable + '<td align="right">' + str(fileSize) + '</td>'
            entryListTable = entryListTable + '<td>' + str(lastModified.strftime("%Y-%m-%d  %H:%M:%S")) + '</td>'
                
            entryListTable = entryListTable + '<td align="center">'
            entryListTable = entryListTable + '<a href="/viewacl?key=' + keyname + '&amp;md5hash=' + md5 + '" title="view/edit ACL">'
#                entryListTable = entryListTable + _('view/edit ACL')
#                entryListTable = entryListTable + 'view/edit ACL'
#            entryListTable = entryListTable + '<img src="view/images/edit.png" width="20" height="20" border="0" alt="view/edit">'
            entryListTable = entryListTable + '<img src="view/images/OctopusIconsScratch/01_Scratch/file_edit.png" width="28" height="28" border="0" alt="view/edit">'
            entryListTable = entryListTable + '</a>'
            entryListTable = entryListTable + '</td>'
            
            entryListTable = entryListTable + '<td align="center">'
            entryListTable = entryListTable + '<tt>' + md5 + '</tt>'
            entryListTable = entryListTable + '</td>'
            
            entryListTable = entryListTable + '</tr>'
        return entryListTable
    
    # responsible for the headline-text of the browse-view
    def buildSelectFileHeadline(self):
#        selectFileHeadline = _('Choose a file to upload')
        selectFileHeadline = 'Choose a file to upload'
        return selectFileHeadline
    
    # responsible for the 'browse-view' to select a file from the file-system
    def buildSelectFile(self, utilities, bucketname, accessKeyId, policy, signature, key):
        # use the GAE blobstore, to store the upload-file as a blob-object. needed for further processes, e.g. RAID-5
        uploadURL = blobstore.create_upload_url('/fileupload')
        
        browse = ''
#        browse = browse + '<form action="/fileupload" method="post" enctype="multipart/form-data">'
        browse = browse + '<form action="' + uploadURL + '" method="post" enctype="multipart/form-data">'
#        browse = browse + '<font color="#954b4b"><em>' +  _('Please enter the key-name, choose an acl and a content-type') + '</em></font>'   
        browse = browse + '<font color="#954b4b"><em>' +  'Please enter the key-name, choose an acl and a content-type' + '</em></font>'
        browse = browse + '<p></p>'
        browse = browse + '<table>'
        browse = browse + '<tr>'
#        browse = browse + '<th align="left">' + _('Key') + '</th>'
#        browse = browse + '<th align="left">' + _('ACL') + '</th>'
#        browse = browse + '<th align="left">' + _('Content-Type') + '</th>'
        browse = browse + '<th align="left">' + 'Key' + '</th>'
        browse = browse + '<th align="left">' + 'ACL' + '</th>'
        browse = browse + '<th align="left">' + 'Content-Type' + '</th>'
        browse = browse + '</tr>'
        
        browse = browse + '<tr>'
        browse = browse + '<td>'
        browse = browse + '<input type="text" name="key" value="" />'
        browse = browse + '</td>'

        # build the selection for the available acl
        browse = browse + '<td>'
        browse = browse + '<select name="acl" size="1">\n'
        browse = browse + '<option selected="selected">----------</option>\n'
        browse = browse + '<option>private</option>\n'
        browse = browse + '<option>authenticated-read</option>\n'
        browse = browse + '<option>public-read</option>\n'
        browse = browse + '<option>public-read-write</option>\n'
        browse = browse + '</select>\n'
        browse = browse + '</td>'
        
        # build the selection for the available content-type(s)
        browse = browse + '<td>'
        browse = browse + '<select name="Content-Type" size="1">\n'
        browse = browse + '<option selected="selected">----------</option>\n'
        browse = browse + '<option>application/octet-stream</option>\n'
        browse = browse + '<option>application/pdf</option>\n'
        browse = browse + '<option>application/zip</option>\n'
        browse = browse + '<option>audio/mp4</option>\n'
        browse = browse + '<option>audio/mpeg</option>\n'
        browse = browse + '<option>audio/ogg</option>\n'
        browse = browse + '<option>audio/vorbis</option>\n'
        browse = browse + '<option>image/gif</option>\n'
        browse = browse + '<option>image/jpeg</option>\n'
        browse = browse + '<option>image/png</option>\n'
        browse = browse + '<option>image/tiff</option>\n'
        browse = browse + '<option>text/html</option>\n'
        browse = browse + '<option>text/plain</option>\n'
        browse = browse + '<option>video/mp4</option>\n'
        browse = browse + '<option>video/mpeg</option>\n'
        browse = browse + '<option>video/ogg</option>\n'
        browse = browse + '</select>\n'
        browse = browse + '</td>'
        
#        browse = browse + '<td>'
#        browse = browse + '<input type="text" name="key" value="braille-schrift_3.gif" />'
#        browse = browse + '</td>'
#        browse = browse + '<td>'
#        browse = browse + '<input type="hidden" name="key" value=""/>\n'
#        browse = browse + '<input type="text" name="acl" value="public-read" />'
#        browse = browse + '</td>'
#        browse = browse + '<td>'
#        browse = browse + '<input type="text" name="content-type" value="image/gif" />'
#        browse = browse + '</td>'
        browse = browse + '</tr>'
        browse = browse + '</table>'
        
        # needed for the file-upload to a s3-compatible-storage-service, but actually not in usage
        browse = browse + '<table>'
        browse = browse + '<tr>'
        browse = browse + '<td>'
        browse = browse + '<input type="hidden" id="success_action_redirect" name="success_action_redirect" value="http://localhost:8088/selectdata">'        
        browse = browse + '<input type="hidden" id="AWSAccessKeyId" name="AWSAccessKeyId" value="' + accessKeyId + '">'
        browse = browse + '<input type="hidden" id="policy" name="policy" value="' + policy + '">'
        browse = browse + '<input type="hidden" id="signature" name="signature" value="' + signature + '">'
        browse = browse + '</td>'
        browse = browse + '</tr>'
        browse = browse + '</table>'
        
        # build the file-upload-field and the buttons
        browse = browse + '<table>'
        browse = browse + '<tr>'
        browse = browse + '<td>'
        browse = browse + '<input type="file" name="file" value="file" size="73" />'
#        browse = browse + '<input type="submit" name="upload" value="' + _('Upload') +'" />'
#        browse = browse + '<input type="reset" name="reset" value="' + _('Reset') +'" />'
        browse = browse + '<input type="submit" name="upload" value="' + 'Upload' +'" />'
        browse = browse + '<input type="reset" name="reset" value="' + 'Reset' +'" />'
        browse = browse + '</td>'
        browse = browse + '</tr>'
        browse = browse + '</table>'
        browse = browse + '</form>'
        
        return browse
    
    # Create the policy document
    def buildPolicyDocument(self, utilities, bucketname):
        # expiration date is specified in ISO 8601 format.
        policyDocument = ''
        policyDocument = policyDocument + '{'
        policyDocument = policyDocument + '"expiration": "2100-01-01T00:00:00Z",'
        policyDocument = policyDocument + '"conditions": ['
        policyDocument = policyDocument + '{"bucket": "' + bucketname + '"}, '
        policyDocument = policyDocument + '["starts-with", "$acl", ""],'          
        policyDocument = policyDocument + '{"success_action_redirect": "http://localhost:8088/selectdata"},'                  # this is for the development-environment     
#        policyDocument = policyDocument + '{"success_action_redirect": "http://cloudoctopus.appspot.com/selectdata"},'      # this is for the productive-environment     
        policyDocument = policyDocument + '["starts-with", "$key", ""],'
        policyDocument = policyDocument + '["starts-with", "$Content-Type", ""]'
        policyDocument = policyDocument + ']'
        policyDocument = policyDocument + '}'
        return policyDocument
    
    # prepare for the select-file-process
    def selectFile(self, utilities, username, bucketname, policy, key):
        credentials = utilities.getCredentials(username)
        results = credentials.fetch(100)
        
        for result in results:
            regionname = result.regionname
            
            if regionname == utilities.getAmazonText() or regionname == utilities.getGoogleText() or regionname == utilities.getOpenStackText():
                secretAccessKeyId = utilities.getSecretAccessKeyByRegionname(username, regionname)
                accessKeyId = utilities.getAccessKeyByRegionname(username, regionname)
                signature = utilities.getSignature(secretAccessKeyId, policy)
                
                selectFile = self.buildSelectFile(utilities, bucketname, accessKeyId, policy, signature, key)
        return selectFile
    
    # gets the available region-names
    def getRegionnames(self, utilities, username):
        credentials = utilities.getCredentials(username)
        results = credentials.fetch(100)
        
        regionnameList = []
        for result in results:
            regionname = result.regionname
            regionnameList.append(regionname)
        return regionnameList

    # gets the entries from the local database OctopusCloudDatabaseRaidFive and return a list with the entries..
    def getEntriesFromLocalDatabaseRaidFive(self, utilities, username):
        entries = utilities.getAllRaidFiveEntriesByUser(username)
        entriesResults = entries.fetch(100)
        
        keyList = []
        for entry in entriesResults:
            keyList.append(entry)
        return keyList
    
    # call the get-method from this class. needed from other classes
    def externalBuilder(self, pSelf, templateValues):
        self.get(pSelf, templateValues)



